/*-------------------------------------------------------------------------
 *
 * encnames.c
 *	  编码名称及其相关处理程序。
 *
 * Portions Copyright (c) 2001-2022, PostgreSQL Global Development Group
 *
 * IDENTIFICATION
 *	  src/common/encnames.c
 *
 *-------------------------------------------------------------------------
 */
#include "c.h"

#include <ctype.h>
#include <unistd.h>

#include "mb/pg_wchar.h"


/* ----------
 * 所有编码名称，按字母顺序排序：		 *** A L P H A B E T I C ***
 *
 * 所有名称必须没有无关字符，搜索例程仅使用
 * isalnum() 字符。这意味着 ISO-8859-1、iso_8859-1 和 Iso8859_1
 * 总是被转换为 'iso88591'。所有名称必须小写。
 *
 * 表中不包含 'cs' 别名（如 csISOLatin1）。需要吗？
 *
 * Karel Zak, 2001年8月
 * ----------
 */
typedef struct pg_encname
{
	const char *name;
	pg_enc		encoding;
} pg_encname;

static const pg_encname pg_encname_tbl[] =
{
	{
		"abc", PG_WIN1258
	},							/* WIN1258 的别名 */
	{
		"alt", PG_WIN866
	},							/* IBM866 */
	{
		"big5", PG_BIG5
	},							/* Big5; 台湾中文多字节集 */
	{
		"euccn", PG_EUC_CN
	},							/* EUC-CN; 简体中文的扩展 Unix 代码 */
	{
		"eucjis2004", PG_EUC_JIS_2004
	},							/* EUC-JIS-2004; 日本语的扩展 UNIX 代码固定
								 * 宽度，标准 JIS X 0213 */
	{
		"eucjp", PG_EUC_JP
	},							/* EUC-JP; 日本语的扩展 UNIX 代码固定宽度，
								 * 标准 OSF */
	{
		"euckr", PG_EUC_KR
	},							/* EUC-KR; 韩语的扩展 Unix 代码，KS
								 * X 1001 标准 */
	{
		"euctw", PG_EUC_TW
	},							/* EUC-TW; 繁体中文的扩展 Unix 代码 */
	{
		"gb18030", PG_GB18030
	},							/* GB18030; GB18030 */
	{
		"gbk", PG_GBK
	},							/* GBK; 中文 Windows 代码页 936
								 * 简体中文 */
	{
		"iso88591", PG_LATIN1
	},							/* ISO-8859-1; RFC1345,KXS2 */
	{
		"iso885910", PG_LATIN6
	},							/* ISO-8859-10; RFC1345,KXS2 */
	{
		"iso885913", PG_LATIN7
	},							/* ISO-8859-13; RFC1345,KXS2 */
	{
		"iso885914", PG_LATIN8
	},							/* ISO-8859-14; RFC1345,KXS2 */
	{
		"iso885915", PG_LATIN9
	},							/* ISO-8859-15; RFC1345,KXS2 */
	{
		"iso885916", PG_LATIN10
	},							/* ISO-8859-16; RFC1345,KXS2 */
	{
		"iso88592", PG_LATIN2
	},							/* ISO-8859-2; RFC1345,KXS2 */
	{
		"iso88593", PG_LATIN3
	},							/* ISO-8859-3; RFC1345,KXS2 */
	{
		"iso88594", PG_LATIN4
	},							/* ISO-8859-4; RFC1345,KXS2 */
	{
		"iso88595", PG_ISO_8859_5
	},							/* ISO-8859-5; RFC1345,KXS2 */
	{
		"iso88596", PG_ISO_8859_6
	},							/* ISO-8859-6; RFC1345,KXS2 */
	{
		"iso88597", PG_ISO_8859_7
	},							/* ISO-8859-7; RFC1345,KXS2 */
	{
		"iso88598", PG_ISO_8859_8
	},							/* ISO-8859-8; RFC1345,KXS2 */
	{
		"iso88599", PG_LATIN5
	},							/* ISO-8859-9; RFC1345,KXS2 */
	{
		"johab", PG_JOHAB
	},							/* JOHAB; 简体中文的扩展 Unix 代码 */
	{
		"koi8", PG_KOI8R
	},							/* _dirty_ KOI8-R 的别名（向后
								 * 兼容性） */
	{
		"koi8r", PG_KOI8R
	},							/* KOI8-R; RFC1489 */
	{
		"koi8u", PG_KOI8U
	},							/* KOI8-U; RFC2319 */
	{
		"latin1", PG_LATIN1
	},							/* ISO-8859-1 的别名 */
	{
		"latin10", PG_LATIN10
	},							/* ISO-8859-16 的别名 */
	{
		"latin2", PG_LATIN2
	},							/* ISO-8859-2 的别名 */
	{
		"latin3", PG_LATIN3
	},							/* ISO-8859-3 的别名 */
	{
		"latin4", PG_LATIN4
	},							/* ISO-8859-4 的别名 */
	{
		"latin5", PG_LATIN5
	},							/* ISO-8859-9 的别名 */
	{
		"latin6", PG_LATIN6
	},							/* ISO-8859-10 的别名 */
	{
		"latin7", PG_LATIN7
	},							/* ISO-8859-13 的别名 */
	{
		"latin8", PG_LATIN8
	},							/* ISO-8859-14 的别名 */
	{
		"latin9", PG_LATIN9
	},							/* ISO-8859-15 的别名 */
	{
		"mskanji", PG_SJIS
	},							/* Shift_JIS 的别名 */
	{
		"muleinternal", PG_MULE_INTERNAL
	},
	{
		"shiftjis", PG_SJIS
	},							/* Shift_JIS; JIS X 0202-1991 */

	{
		"shiftjis2004", PG_SHIFT_JIS_2004
	},							/* SHIFT-JIS-2004; 标准 JIS X 0213 的日本
								 * Shift JIS */
	{
		"sjis", PG_SJIS
	},							/* Shift_JIS 的别名 */
	{
		"sqlascii", PG_SQL_ASCII
	},
	{
		"tcvn", PG_WIN1258
	},							/* WIN1258 的别名 */
	{
		"tcvn5712", PG_WIN1258
	},							/* WIN1258 的别名 */
	{
		"uhc", PG_UHC
	},							/* UHC; 韩语 Windows 代码页 949 */
	{
		"unicode", PG_UTF8
	},							/* UTF8 的别名 */
	{
		"utf8", PG_UTF8
	},							/* UTF8 的别名 */
	{
		"vscii", PG_WIN1258
	},							/* WIN1258 的别名 */
	{
		"win", PG_WIN1251
	},							/* _dirty_ Windows-1251 的别名（向后
								 * 兼容性） */
	{
		"win1250", PG_WIN1250
	},							/* Windows-1250 的别名 */
	{
		"win1251", PG_WIN1251
	},							/* Windows-1251 的别名 */
	{
		"win1252", PG_WIN1252
	},							/* Windows-1252 的别名 */
	{
		"win1253", PG_WIN1253
	},							/* Windows-1253 的别名 */
	{
		"win1254", PG_WIN1254
	},							/* Windows-1254 的别名 */
	{
		"win1255", PG_WIN1255
	},							/* Windows-1255 的别名 */
	{
		"win1256", PG_WIN1256
	},							/* Windows-1256 的别名 */
	{
		"win1257", PG_WIN1257
	},							/* Windows-1257 的别名 */
	{
		"win1258", PG_WIN1258
	},							/* WIN1258 的别名 */
	{
		"win866", PG_WIN866
	},							/* IBM866 */
	{
		"win874", PG_WIN874
	},							/* Windows-874 的别名 */
	{
		"win932", PG_SJIS
	},							/* Shift_JIS 的别名 */
	{
		"win936", PG_GBK
	},							/* GBK 的别名 */
	{
		"win949", PG_UHC
	},							/* UHC 的别名 */
	{
		"win950", PG_BIG5
	},							/* BIG5 的别名 */
	{
		"windows1250", PG_WIN1250
	},							/* Windows-1251; 微软 */
	{
		"windows1251", PG_WIN1251
	},							/* Windows-1251; 微软 */
	{
		"windows1252", PG_WIN1252
	},							/* Windows-1252; Microsoft */
	{
		"windows1253", PG_WIN1253
	},							/* Windows-1253; Microsoft */
	{
		"windows1254", PG_WIN1254
	},							/* Windows-1254; Microsoft */
	{
		"windows1255", PG_WIN1255
	},							/* Windows-1255; Microsoft */
	{
		"windows1256", PG_WIN1256
	},							/* Windows-1256; Microsoft */
	{
		"windows1257", PG_WIN1257
	},							/* Windows-1257; Microsoft */
	{
		"windows1258", PG_WIN1258
	},							/* Windows-1258; Microsoft */
	{
		"windows866", PG_WIN866
	},							/* IBM866 */
	{
		"windows874", PG_WIN874
	},							/* Windows-874; Microsoft */
	{
		"windows932", PG_SJIS
	},							/* Shift_JIS 的别名 */
	{
		"windows936", PG_GBK
	},							/* GBK 的别名 */
	{
		"windows949", PG_UHC
	},							/* UHC 的别名 */
	{
		"windows950", PG_BIG5
	}							/* BIG5 的别名 */
};

/* ----------
 * 这些是"官方"编码名称。
 * XXX 必须按 mb/pg_wchar.h 中 enum pg_enc 的相同顺序排序
 * ----------
 */
#ifndef WIN32
#define DEF_ENC2NAME(name, codepage) { #name, PG_##name }
#else
#define DEF_ENC2NAME(name, codepage) { #name, PG_##name, codepage }
#endif

const pg_enc2name pg_enc2name_tbl[] =
{
	DEF_ENC2NAME(SQL_ASCII, 0),
	DEF_ENC2NAME(EUC_JP, 20932),
	DEF_ENC2NAME(EUC_CN, 20936),
	DEF_ENC2NAME(EUC_KR, 51949),
	DEF_ENC2NAME(EUC_TW, 0),
	DEF_ENC2NAME(EUC_JIS_2004, 20932),
	DEF_ENC2NAME(UTF8, 65001),
	DEF_ENC2NAME(MULE_INTERNAL, 0),
	DEF_ENC2NAME(LATIN1, 28591),
	DEF_ENC2NAME(LATIN2, 28592),
	DEF_ENC2NAME(LATIN3, 28593),
	DEF_ENC2NAME(LATIN4, 28594),
	DEF_ENC2NAME(LATIN5, 28599),
	DEF_ENC2NAME(LATIN6, 0),
	DEF_ENC2NAME(LATIN7, 0),
	DEF_ENC2NAME(LATIN8, 0),
	DEF_ENC2NAME(LATIN9, 28605),
	DEF_ENC2NAME(LATIN10, 0),
	DEF_ENC2NAME(WIN1256, 1256),
	DEF_ENC2NAME(WIN1258, 1258),
	DEF_ENC2NAME(WIN866, 866),
	DEF_ENC2NAME(WIN874, 874),
	DEF_ENC2NAME(KOI8R, 20866),
	DEF_ENC2NAME(WIN1251, 1251),
	DEF_ENC2NAME(WIN1252, 1252),
	DEF_ENC2NAME(ISO_8859_5, 28595),
	DEF_ENC2NAME(ISO_8859_6, 28596),
	DEF_ENC2NAME(ISO_8859_7, 28597),
	DEF_ENC2NAME(ISO_8859_8, 28598),
	DEF_ENC2NAME(WIN1250, 1250),
	DEF_ENC2NAME(WIN1253, 1253),
	DEF_ENC2NAME(WIN1254, 1254),
	DEF_ENC2NAME(WIN1255, 1255),
	DEF_ENC2NAME(WIN1257, 1257),
	DEF_ENC2NAME(KOI8U, 21866),
	DEF_ENC2NAME(SJIS, 932),
	DEF_ENC2NAME(BIG5, 950),
	DEF_ENC2NAME(GBK, 936),
	DEF_ENC2NAME(UHC, 949),
	DEF_ENC2NAME(GB18030, 54936),
	DEF_ENC2NAME(JOHAB, 0),
	DEF_ENC2NAME(SHIFT_JIS_2004, 932)
};

/* ----------
 * 这些是 gettext 的编码名称。
 *
 * 这涵盖了除了 MULE_INTERNAL 之外的所有编码，它对 gettext 来说是陌生的。
 * ----------
 */
const pg_enc2gettext pg_enc2gettext_tbl[] =
{
	{PG_SQL_ASCII, "US-ASCII"},
	{PG_UTF8, "UTF-8"},
	{PG_LATIN1, "LATIN1"},
	{PG_LATIN2, "LATIN2"},
	{PG_LATIN3, "LATIN3"},
	{PG_LATIN4, "LATIN4"},
	{PG_ISO_8859_5, "ISO-8859-5"},
	{PG_ISO_8859_6, "ISO_8859-6"},
	{PG_ISO_8859_7, "ISO-8859-7"},
	{PG_ISO_8859_8, "ISO-8859-8"},
	{PG_LATIN5, "LATIN5"},
	{PG_LATIN6, "LATIN6"},
	{PG_LATIN7, "LATIN7"},
	{PG_LATIN8, "LATIN8"},
	{PG_LATIN9, "LATIN-9"},
	{PG_LATIN10, "LATIN10"},
	{PG_KOI8R, "KOI8-R"},
	{PG_KOI8U, "KOI8-U"},
	{PG_WIN1250, "CP1250"},
	{PG_WIN1251, "CP1251"},
	{PG_WIN1252, "CP1252"},
	{PG_WIN1253, "CP1253"},
	{PG_WIN1254, "CP1254"},
	{PG_WIN1255, "CP1255"},
	{PG_WIN1256, "CP1256"},
	{PG_WIN1257, "CP1257"},
	{PG_WIN1258, "CP1258"},
	{PG_WIN866, "CP866"},
	{PG_WIN874, "CP874"},
	{PG_EUC_CN, "EUC-CN"},
	{PG_EUC_JP, "EUC-JP"},
	{PG_EUC_KR, "EUC-KR"},
	{PG_EUC_TW, "EUC-TW"},
	{PG_EUC_JIS_2004, "EUC-JP"},
	{PG_SJIS, "SHIFT-JIS"},
	{PG_BIG5, "BIG5"},
	{PG_GBK, "GBK"},
	{PG_UHC, "UHC"},
	{PG_GB18030, "GB18030"},
	{PG_JOHAB, "JOHAB"},
	{PG_SHIFT_JIS_2004, "SHIFT_JISX0213"},
	{0, NULL}
};


/*
 * ICU 的编码名称表（目前只覆盖后端编码）
 *
 * 参考: <https://ssl.icu-project.org/icu-bin/convexp>
 *
 * NULL 条目不被 ICU 支持，或者它们的映射不明确。
 */
static const char *const pg_enc2icu_tbl[] =
{
	NULL,						/* PG_SQL_ASCII */
	"EUC-JP",					/* PG_EUC_JP */
	"EUC-CN",					/* PG_EUC_CN */
	"EUC-KR",					/* PG_EUC_KR */
	"EUC-TW",					/* PG_EUC_TW */
	NULL,						/* PG_EUC_JIS_2004 */
	"UTF-8",					/* PG_UTF8 */
	NULL,						/* PG_MULE_INTERNAL */
	"ISO-8859-1",				/* PG_LATIN1 */
	"ISO-8859-2",				/* PG_LATIN2 */
	"ISO-8859-3",				/* PG_LATIN3 */
	"ISO-8859-4",				/* PG_LATIN4 */
	"ISO-8859-9",				/* PG_LATIN5 */
	"ISO-8859-10",				/* PG_LATIN6 */
	"ISO-8859-13",				/* PG_LATIN7 */
	"ISO-8859-14",				/* PG_LATIN8 */
	"ISO-8859-15",				/* PG_LATIN9 */
	NULL,						/* PG_LATIN10 */
	"CP1256",					/* PG_WIN1256 */
	"CP1258",					/* PG_WIN1258 */
	"CP866",					/* PG_WIN866 */
	NULL,						/* PG_WIN874 */
	"KOI8-R",					/* PG_KOI8R */
	"CP1251",					/* PG_WIN1251 */
	"CP1252",					/* PG_WIN1252 */
	"ISO-8859-5",				/* PG_ISO_8859_5 */
	"ISO-8859-6",				/* PG_ISO_8859_6 */
	"ISO-8859-7",				/* PG_ISO_8859_7 */
	"ISO-8859-8",				/* PG_ISO_8859_8 */
	"CP1250",					/* PG_WIN1250 */
	"CP1253",					/* PG_WIN1253 */
	"CP1254",					/* PG_WIN1254 */
	"CP1255",					/* PG_WIN1255 */
	"CP1257",					/* PG_WIN1257 */
	"KOI8-U",					/* PG_KOI8U */
#ifdef FDD
    NULL,					    /* Shift JIS (Windows-932) */
	NULL,					    /* Big5 (Windows-950) */
	NULL,						/* GBK (Windows-936) */
	NULL,						/* UHC (Windows-949) */
	"GB18030",					/* GB18030 */
#endif

};


/*
 * 这个编码被 ICU 支持吗？
 */
bool is_encoding_supported_by_icu(int fc_encoding)
{
	if (!PG_VALID_BE_ENCODING(fc_encoding))
		return false;
	return (pg_enc2icu_tbl[fc_encoding] != NULL);
}

/*
 * 返回 ICU 的编码名称，如果不支持则返回 NULL
 */
const char * get_encoding_name_for_icu(int fc_encoding)
{
#ifdef FDD
	StaticAssertStmt(lengthof(pg_enc2icu_tbl) == PG_GB18030 + 1,
					 "pg_enc2icu_tbl incomplete");
#else
	StaticAssertStmt(lengthof(pg_enc2icu_tbl) == PG_ENCODING_BE_LAST + 1,
					 "pg_enc2icu_tbl incomplete");
#endif

	if (!PG_VALID_BE_ENCODING(fc_encoding))
		return NULL;
	return pg_enc2icu_tbl[fc_encoding];
}


/* ----------
 * 编码检查，对于错误返回 -1 否则返回编码 ID
 * ----------
 */
int pg_valid_client_encoding(const char *fc_name)
{
	int			fc_enc;

	if ((fc_enc = pg_char_to_encoding(fc_name)) < 0)
		return -1;

	if (!PG_VALID_FE_ENCODING(fc_enc))
		return -1;

	return fc_enc;
}

int pg_valid_server_encoding(const char *fc_name)
{
	int			fc_enc;

	if ((fc_enc = pg_char_to_encoding(fc_name)) < 0)
		return -1;

	if (!PG_VALID_BE_ENCODING(fc_enc))
		return -1;

	return fc_enc;
}

int pg_valid_server_encoding_id(int fc_encoding)
{
	return PG_VALID_BE_ENCODING(fc_encoding);
}

/*
 * 从编码名称中移除无关字符，存储在 *newkey 中
 *
 * （调用者负责提供一个足够大的缓冲区）
 */
static char * fc_clean_encoding_name(const char *fc_key, char *fc_newkey)
{
	const char *fc_p;
	char	   *fc_np;

	for (fc_p = fc_key, fc_np = fc_newkey; *fc_p != '\0'; fc_p++)
	{
		if (isalnum((unsigned char) *fc_p))
		{
			if (*fc_p >= 'A' && *fc_p <= 'Z')
				*fc_np++ = *fc_p + 'a' - 'A';
			else
				*fc_np++ = *fc_p;
		}
	}
	*fc_np = '\0';
	return fc_newkey;
}

/*
 * 按编码名称搜索编码
 *
 * 返回编码 ID，如果不被识别则返回 -1
 */
int pg_char_to_encoding(const char *fc_name)
{
	unsigned int fc_nel = lengthof(pg_encname_tbl);
	const pg_encname *fc_base = pg_encname_tbl,
			   *fc_last = fc_base + fc_nel - 1,
			   *fc_position;
	int			fc_result;
#ifdef FDD //cppcheck
	char		fc_buff[NAMEDATALEN] = {'\0'},
#else
	char		buff[NAMEDATALEN],
#endif
			   *fc_key;

	if (fc_name == NULL || *fc_name == '\0')
		return -1;

	if (strlen(fc_name) >= NAMEDATALEN)
		return -1;				/* 它确实不在表中 */

	fc_key = fc_clean_encoding_name(fc_name, fc_buff);

	while (fc_last >= fc_base)
	{
		fc_position = fc_base + ((fc_last - fc_base) >> 1);
		fc_result = fc_key[0] - fc_position->name[0];

		if (fc_result == 0)
		{
			fc_result = strcmp(fc_key, fc_position->name);
			if (fc_result == 0)
				return fc_position->encoding;
		}
		if (fc_result < 0)
			fc_last = fc_position - 1;
		else
			fc_base = fc_position + 1;
	}
	return -1;
}

const char * pg_encoding_to_char(int fc_encoding)
{
	if (PG_VALID_ENCODING(fc_encoding))
	{
		const pg_enc2name *fc_p = &pg_enc2name_tbl[fc_encoding];

		Assert(fc_encoding == fc_p->encoding);
		return fc_p->name;
	}
	return "";
}
